package seekting.demo2017.activity.util;

import android.util.Base64;
import android.util.Log;

import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


/**
 * Created by seekting on 17-3-27.
 */

public class Liba {
    public static final boolean DEBUG = true;
    private static final boolean USE_OLD = false;
    public static final String TAG = "Liba";
    private static byte[] pwd = null;

    static {
        if (USE_OLD) {
            pwd = new byte[]{(byte) 0x12, (byte) 0x3e, (byte) 0xff, (byte) 0xd8, (byte) 0x59, (byte) 0x65, (byte) 0xdf, (byte) 0xfc, (byte) 0xff, (byte) 0xcf, (byte) 0xdf, (byte) 0xad, (byte) 0xf1, (byte) 0x23, (byte) 0x21, (byte) 0x32};
        } else {
            pwd = new byte[]{(byte) 0x22, (byte) 0x3c, (byte) 0x6f, (byte) 0xd8, (byte) 0x59, (byte) 0x65, (byte) 0x1f, (byte) 0x3c, (byte) 0xff, (byte) 0xcf, (byte) 0xdf, (byte) 0x13, (byte) 0x11, (byte) 0x23, (byte) 0x21, (byte) 0x42};
        }

        pwd = new byte[]{(byte) 0x32, (byte) 0x8f, (byte) 0x4c, (byte) 0x3d, (byte) 0x12, (byte) 0x45, (byte) 0xfc, (byte) 0xfc, (byte) 0xdc, (byte) 0xac, (byte) 0x22, (byte) 0x78, (byte) 0x13
                , (byte) 0x3a, (byte) 0x4f, (byte) 0xca};
    }


    public static final byte[] IV = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    public static final IvParameterSpec IVSPEC = new IvParameterSpec(IV);

    public synchronized static String encode(String inputStr) {
        if (DEBUG) {
            Log.d(TAG, "encode.加密前" + inputStr);
        }
        long time = System.currentTimeMillis();
        byte[] data = inputStr.getBytes();
        int len = data.length;
        int r = len % 16;
        int padding = 16 - r;

        byte[] input = new byte[len + padding];
        System.arraycopy(data, 0, input, 0, len);
        for (int i = len; i < input.length; i++) {
            input[i] = (byte) padding;
        }
        byte[] output = new byte[len + padding];
        boolean suc = f2(input, output);
        if (DEBUG) {
            long wast = System.currentTimeMillis() - time;
            Log.d(TAG, "encode.wast=" + wast + ",suc=" + suc);
        }
        if (suc) {
            //单纯base64还不行，传输的时候会把+号变成空格，所以要urlEncode一下
            String result =
                    URLEncoder.encode(Base64.encodeToString(output, Base64.DEFAULT));
            if (DEBUG) {
                Log.d(TAG, "encode.加密后" + result);
            }
            return result;
        }
        if (DEBUG) {
            Log.d(TAG, "encode.加密失败");
        }
        return null;

    }

    /**
     * //12,3e,ff,d8,59,65,df,fc,ff,cf,df,ad,f1,23,21,32
     *
     * @param input
     * @param output
     * @return
     */
    private static boolean f2(byte[] input, byte[] output) {

        try {
            SecretKeySpec key = new SecretKeySpec(pwd, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, key, IVSPEC);// 初始化
            byte[] result = cipher.doFinal(input);
            for (int i = 0; i < result.length; i++) {
                output[i] = result[i];
            }
        } catch (Exception e) {
            if (DEBUG) {
                Log.e(TAG, "f2.", e);
            }
            return false;
        }

        return true;


    }

    private static boolean f3(byte[] input, byte[] output) {
        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(pwd, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, IVSPEC);// 初始化
            byte[] result = cipher.doFinal(input);
            for (int i = 0; i < result.length; i++) {
                output[i] = result[i];
            }
        } catch (Exception e) {
            if (DEBUG) {
                Log.e(TAG, "f2.", e);
            }
            return false;
        }
        return true;

    }

    public synchronized static String decode(String inputStr) {
        if (inputStr == null) {
            if (DEBUG) {
                Log.d(TAG, "Liba.decode() inputStr=null!");
            }
            return null;
        }
        String urlDecoded = URLDecoder.decode(inputStr);
        long time = System.currentTimeMillis();
        try {
            byte[] input = Base64.decode(urlDecoded, Base64.DEFAULT);
            int len = input.length;
            //看加密的时候补了多少位

            byte[] output = new byte[len];
            boolean suc = f3(input, output);
            if (DEBUG) {
                long wast = System.currentTimeMillis() - time;
                Log.d(TAG, "decode.wast=" + wast + ",suc=" + suc);
            }
            if (suc) {
                byte padding = output[len - 1];
                String result = new String(output, 0, len - padding);
                if (DEBUG) {
                    Log.d(TAG, "Liba.decode() 密文：" + inputStr);
                    Log.d(TAG, "Liba.decode()解密后：" + result);
                }
                return result;
            } else {
                return null;
            }
        } catch (Throwable e) {
            if (DEBUG) {
                Log.w(TAG, "Liba.decode() 解密失败：" + inputStr, e);
                e.printStackTrace();
            }
            return null;
        }
    }

}
